// File: KeyRecommander.cpp
//
// Created by 唐建 on 2023/12/1.
//

#include "Logger.h"
#include "Configuration.h"
#include "CacheManager.h"
#include "../Reactor/Thread.h"
#include "web/KeyRecommander.h"
#include "web/DistanceTool.hpp"
#include "web/io_preamble.h"
#include "web/ProtocolParser.h"
#include "web/SplitTool.hpp"
#include <utility>

using json = nlohmann::json;

Dict *Dict::_pDictZh = nullptr;
Dict *Dict::_pDictEn = nullptr;
pthread_once_t Dict::_pOnceEn = PTHREAD_ONCE_INIT;
pthread_once_t Dict::_pOnceZh = PTHREAD_ONCE_INIT;

Dict *Dict::getInstance(int dictType)
{
    if (dictType == 2) {
        pthread_once(&_pOnceEn, dictInitEn);
        return _pDictEn;
    } else if (dictType == 1) {
        pthread_once(&_pOnceZh, dictInitZh);
        return _pDictZh;
    } else {
        LogError("非法的字典类型");
        exit(-1);
    }
};

Dict::Dict(int dictType) : _dictType(dictType)
{
    //推荐词索引库 路径
    //std::string dbpath;
    //
    //if (dictType == 1) {
    //    dbpath = Configuration::getInstance()->getConfigValue("");
    //} else if (dictType == 2) {
    //    dbpath = Configuration::getInstance()->getConfigValue("");
    //}
    init(std::to_string(dictType));
}

void Dict::dictInitZh()
{
    _pDictZh = new Dict(1);
    atexit(destroy);
}

void Dict::dictInitEn()
{
    _pDictEn = new Dict(2);
    atexit(destroy);
}

void Dict::destroy()
{
    if (_pDictZh) {
        delete _pDictZh;
        _pDictZh = nullptr;
    }
    if (_pDictEn) {
        delete _pDictEn;
        _pDictEn = nullptr;
    }
}

void Dict::init(const std::string &dictDBPath)
{
    //读词典 读索引
    ifstream dictLibF, dictIndexLibF;
    string dictLibP, dictIndexP;
    //string dictLibP = dictDBPath + "/dict.lib";
    //string dictIndexP = dictDBPath + "/dictIndex.lib";

    if (dictDBPath == "1") {
        dictLibP = Configuration::getInstance()->getConfigValue("CN_DICT_OUTPUT_PATH");
        dictIndexP = Configuration::getInstance()->getConfigValue("CN_INDEX_OUTPUT_PATH");
    } else if (dictDBPath == "2") {
        dictLibP = Configuration::getInstance()->getConfigValue("EN_DICT_OUTPUT_PATH");
        dictIndexP = Configuration::getInstance()->getConfigValue("EN_INDEX_OUTPUT_PATH");
    }

    if (!open_file(dictLibF, dictLibP)) {
        LogError("推荐字典库文件不存在 filepath : " + dictLibP);
        return;
    }

    if (!open_file(dictIndexLibF, dictIndexP)) {
        LogError("推荐字典库索引文件不存在 filepath : " + dictIndexP);
        return;
    }

    // 构建 dict vector (lin_no)-(word freq)
    string textLine, word;
    int freq;
    vector<string> lines_of_text;
    while (getline(dictLibF, textLine)) {
        istringstream iss(textLine);
        iss >> word;
        iss >> freq;
        _dict.emplace_back(word, freq);
    }

    //构建 dictIndex map (word)-(set<line_no>)
    int line_no;
    set<int> line_nos;
    while (getline(dictIndexLibF, textLine)) {
        line_nos.clear();
        istringstream iss(textLine);
        iss >> word;
        while (iss >> line_no, !iss.eof()) {
            //_indexTable[word].insert(line_no); //效率问题每次都要查map
            line_nos.insert(line_no);
        }
        _indexTable.emplace(word, line_nos);
    }
}

Dict::DictVector &Dict::getIndexTable()
{
    return _dict;
}

Dict::IndexTable &Dict::getDict()
{
    return _indexTable;
}

Dict::WordVectorPtr Dict::doQuery(const std::string &word)
{
    WordVectorPtr matchVector(new std::vector<std::pair<std::string, int>>());
    //遍历字符
    for (size_t i = 0; i < word.length();) {
        int cplen = 1;
        if ((word[i] & 0xf8) == 0xf0) cplen = 4;     // 占用4个字节，前5位为11110
        else if ((word[i] & 0xf0) == 0xe0) cplen = 3; // 占用3个字节，前4位为1110
        else if ((word[i] & 0xe0) == 0xc0) cplen = 2; // 占用2个字节，前3位为110
        if ((i + cplen) > word.length()) cplen = 1;

        //搜索字符对应的单词
        //cout << word.substr(i, cplen) << endl;
        string tarword = word.substr(i, cplen);
        auto it = _indexTable.find(tarword);
        if (it != _indexTable.end()) {
            for (const auto &item: it->second) {
                auto wordAndFreq = _dict[item];
                matchVector->emplace_back(wordAndFreq.first, wordAndFreq.second);
            }
        }

        i += cplen;
    }

    return matchVector;
}

KeyRecommander::KeyRecommander(std::string sought, TcpConnectionPtr coon)
        : _sought(sought), _coon(std::move(coon)), _zhIN(containZh(sought))
{}

bool KeyRecommander::containZh(string &sought)
{
    char c;
    auto str = sought.c_str();
    while (true) {
        c = *str++;
        if (c == 0) break;  //如果到字符串尾则说明该字符串没有中文字符
        if (c & 0x80)        //如果字符高位为1且下一字符高位也是1则有中文字符
            if (*str & 0x80) return true;
    }
    return false;
}

std::string KeyRecommander::returnNoAnswer()
{
    nlohmann::json msg = "没有搜索到!";
    string returnMsg = ProtocolParser::getSendmsg("200", msg);
    return returnMsg;
}

std::string KeyRecommander::doQuery()
{
    //查询 thread local cache
    string cacheStr = CacheManager::getInstance()->getCache(atoi(name)).SearchKeyword(_sought);
    if (!cacheStr.empty()) {
        cacheStr += '\n';
        _coon->sendInLoop(cacheStr);
        cout << cacheStr << endl;
        return "1";
    }

    // _sought 查询的词汇 分词
    auto keyWordVector = SplitToolCppJieba::getInstance()->cut(_sought);
    // _sought 查询的词汇 分字
    //std::vector<std::string> characters;
    //int len = _sought.length();
    //int i = 0;
    //
    //while (i < len) {
    //    int bytes = DistanceTool::nBytesCode(_sought[i]);
    //    std::string character = _sought.substr(i, bytes);
    //    characters.push_back(character);
    //    i += bytes;
    //}

    // Dictionary 选择搜索的词库
    Dict *pDict = Dict::getInstance(_zhIN ? 1 : 2);

    // 遍历分词求并集
    unordered_set<string> matchSet;

    for (const auto &curSearchWord: keyWordVector) {
        //匹配的集合
        auto matchVector = pDict->doQuery(curSearchWord);
        //遍历匹配集合
        for (const auto &matchWordAndFreq: *matchVector.get()) {
            //去重
            if (matchSet.count(matchWordAndFreq.first) == 0) {
                matchSet.insert(matchWordAndFreq.first);
            } else {
                continue;
            }
            //放入优先队列
            _priQue.emplace(matchWordAndFreq.first,
                            matchWordAndFreq.second,
                            DistanceTool::editDistance(matchWordAndFreq.first, curSearchWord));
        }
    }

    // 返回json格式的文件
    // 处理分页
    int pageSize = 5;
    vector<CandidateResult> result;
    // 判读数据条数 是否满足搜索条件 返回 out of range
    if (_priQue.empty()) {
        string send = returnNoAnswer();
        send += '\n';
        _coon->sendInLoop(send);
        CacheManager::getInstance()->getCache(atoi(name)).addPendingList(_sought, send);
        return send;
    }
    for (int i = 0; i < pageSize; ++i) {
        result.push_back(_priQue.top());
        _priQue.pop();
    }
    json j = result;
    auto sendJ = ProtocolParser::getSendmsg( "100",j);
    string send = sendJ.dump() + '\n';
    LogDebug(send);
    _coon->sendInLoop(send);

    CacheManager::getInstance()->getCache(atoi(name)).addPendingList(_sought, sendJ.dump());
    return "1";
}

CandidateResult::CandidateResult(string word, int freq, int dist)
        : _word(std::move(word)), _freq(freq), _dist(dist)
{}
